package dtm

import (
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
	"gitee.com/xuyiping_admin/pkg/xerr"
	"go.uber.org/zap"
	"kpt-dtm/model/dtm"
	"kpt-dtm/pkg"
	"kpt-dtm/service/http"
	"net/url"
	"strings"
	"time"
)

const (
	DtmType = "dtm"
	YynType = "yyn"

	LoginURl       = "/api/auth/jwt"
	CompanyListUrl = "/api/odata/company"

	CompanyTokenUrl        = "/api/auth/companytoken?companyId="
	CompanyRefreshTokenUrl = "/api/auth/refreshtoken"

	SupportSettingsUrl = "/api/support/settings"
	SupportVersionUrl  = "/api/support/version"
	LanguagesUrl       = "/api/support/langs"
	LangUpdateUrl      = "/api/support/updatelang"

	ConfigurationUrl = "/api/configuration"

	MachineTypesUrl  = "/api/odata/Machine/GetMachineTypes()"
	MachinesCountUrl = "/api/odata/Machine/$count"
	MachinesUrl      = "/api/odata/Machine"

	RefusedByDayListUrl = "/api/odata/report/RefusedByDay()"
	BatchHistListUrl    = "/api/odata/report/BatchHist()"
	BatchHistDetailUrl  = "/api/odata/report/BatchHistDetail"
	FormulationListUrl  = "/api/odata/Recipe"

	BatchUrl = "/api/odata/Batch"
)

var (
	UserTokenValue    string
	CompanyTokenValue string
)

type PaginateHandleFunc func(ctx context.Context, skip int, pastureId int64) (interface{}, error)

func (s *StoreEntry) Common(ctx context.Context, pastureId int64, dtm, path string) (interface{}, error) {
	switch dtm {
	case DtmType:
		return s.DtmCommon(ctx, pastureId, path)
	case YynType:
		return s.YynCommon(ctx, pastureId, path)
	}
	return nil, nil
}

func (s *StoreEntry) DtmCommon(ctx context.Context, pastureId int64, path string) (interface{}, error) {
	if err := s.IsCheckCompanyToken(ctx, pastureId); err != nil {
		return nil, xerr.WithStack(err)
	}

	var (
		res interface{}
		err error
	)
	switch path {
	case "login":
		res, err = s.Login(ctx, pastureId)
	case "company_list":
		res, err = s.CompanyList(ctx, pastureId)
	case "company_token":
		res, err = s.CompanyToken(ctx, pastureId)
	case "refresh_company_token":
		res, err = s.CompanyRefreshToken(ctx, pastureId)
	case "support_langs":
		res, err = s.SupportedLanguages(ctx, pastureId)
	case "update_lang":
		err = s.UpdateLanguages(ctx, pastureId)
	case "support_setting":
		res, err = s.SupportSettings(ctx, pastureId)
	case "machine_types":
		res, err = s.MachineTypes(ctx, pastureId)
	case "machines":
		res, err = s.Machines(ctx, pastureId)
	case "machines_count":
		res, err = s.MachinesCount(ctx, pastureId)
	case "pen_count":
		res, err = s.CustomPenCount(ctx, pastureId)
	case "pen":
		res, err = s.GetPen(ctx, 4, pastureId)
	case "pen_list":
		res, err = s.CustomPenList(ctx, pastureId)
	case "create_pen":
		res, err = s.CreatePen(ctx, nil, pastureId)
	case "house_to_dtm_pen":
		yConfig, err := s.GetYConfig(pastureId)
		if err != nil {
			return nil, xerr.WithStack(err)
		}
		err = s.YynHouseInfoToDtmPen(ctx, pastureId, yConfig)
	case "data_init":
		err = s.DataHandle()
	case "batch_hist_detail":
		res, err = s.BatchHistDetail(ctx, 8, pastureId)
	}
	return res, err
}

// Login 登录
func (s *StoreEntry) Login(ctx context.Context, pastureId int64) (*dtm.LoginResponse, error) {
	req := &dtm.LoginRequest{
		GrantType: "password",
		Username:  s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].UserName,
		Password:  s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Password,
		Scope:     "dtm8",
		Lang:      "zh-CN",
	}
	urlPath := fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].LoginUrl, LoginURl)
	zaplog.Info("Login", zap.Any("urlPath", urlPath), zap.Any("req", req))
	res, err := s.HttpClient.DoPost(urlPath, req, []*http.Header{
		&http.Header{
			Key:   "Host",
			Value: strings.TrimPrefix(urlPath, "https://"),
		},
	})

	if err != nil {
		zaplog.Error("Login", zap.Any("jwt", fmt.Sprintf("login dtm error: %v", err)))
		return nil, xerr.WithStack(err)
	}

	response := &dtm.LoginResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	if response.Token == "" {
		return nil, xerr.WithStack(xerr.New("token is empty"))
	}
	UserTokenValue = response.Token
	return response, nil
}

// CompanyList 获取当前用户名下公司列表
func (s *StoreEntry) CompanyList(ctx context.Context, pastureId int64) (*dtm.CompanyListResponse, error) {
	tokenRes, err := s.Login(ctx, pastureId)
	if err != nil {
		return nil, err
	}

	if tokenRes.Token == "" {
		return nil, xerr.WithStack(xerr.New("token is empty"))
	}

	companyListUrl := fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, CompanyListUrl)
	res, err := s.HttpClient.DoGet(companyListUrl, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", tokenRes.Token),
		},
	})
	if err != nil {
		zaplog.Error("CompanyList",
			zap.Any("url", companyListUrl),
			zap.Any("err", err),
			zap.Any("res", string(res)),
			zap.Any("login_token", tokenRes.Token))
		return nil, xerr.WithStack(err)
	}

	response := &dtm.CompanyListResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

func (s *StoreEntry) GetCompanyId(ctx context.Context, pastureId int64) (int64, error) {
	companyList, err := s.CompanyList(ctx, pastureId)
	if err != nil {
		return 0, xerr.WithStack(err)
	}
	if companyList.Value == nil || len(companyList.Value) == 0 {
		return 0, xerr.WithStack(xerr.New("company list is empty"))
	}
	zaplog.Info("GetCompanyId", zap.Any("companyList", companyList))

	for _, v := range companyList.Value {
		if v.Code != s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyCode {
			continue
		}
		return v.CompanyId, nil
	}
	return 0, xerr.WithStack(xerr.New("company not found"))
}

// CompanyToken 获取公司token
func (s *StoreEntry) CompanyToken(ctx context.Context, pastureId int64) (*dtm.CompanyTokenResponse, error) {
	var (
		err       error
		companyId int64
	)
	companyId, err = s.GetCompanyId(ctx, pastureId)
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	if companyId == 0 {
		return nil, xerr.WithStack(xerr.New("company id is empty"))
	}

	companyListUrl := fmt.Sprintf("%s%s%d", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, CompanyTokenUrl, companyId)
	res, err := s.HttpClient.DoGet(companyListUrl, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", UserTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	response := &dtm.CompanyTokenResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	CompanyTokenValue = response.Token
	return response, nil
}

// CompanyRefreshToken 刷新公司token
func (s *StoreEntry) CompanyRefreshToken(ctx context.Context, pastureId int64) (*dtm.CompanyTokenResponse, error) {
	urlPath := fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, CompanyRefreshTokenUrl)
	res, err := s.HttpClient.DoGet(urlPath, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	response := &dtm.CompanyTokenResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	CompanyTokenValue = response.Token
	return response, err
}

// SupportedLanguages 获取支持的语言列表 基本配置
func (s *StoreEntry) SupportedLanguages(ctx context.Context, pastureId int64) ([]string, error) {
	var langs []string
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, LanguagesUrl), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	if err = json.Unmarshal(res, &langs); err != nil {
		return nil, xerr.WithStack(err)
	}
	return langs, nil
}

// UpdateLanguages 更新语言
func (s *StoreEntry) UpdateLanguages(ctx context.Context, pastureId int64) error {
	req := &dtm.UpdateLanguageRequest{
		Lang: "zh-CN",
	}
	_, err := s.HttpClient.DoPut(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, LangUpdateUrl), req, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	return err
}

func (s *StoreEntry) SupportSettings(ctx context.Context, pastureId int64) ([]*dtm.SupportSettingsResponse, error) {
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, SupportSettingsUrl), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	response := make([]*dtm.SupportSettingsResponse, 0)
	if err = json.Unmarshal(res, &response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

func (s *StoreEntry) SupportVersion(ctx context.Context, pastureId int64) (*dtm.SupportVersionResponse, error) {
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, SupportVersionUrl), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	response := &dtm.SupportVersionResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

func (s *StoreEntry) Configurations(ctx context.Context, pastureId int64) (*dtm.ConfigurationsResponse, error) {
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, ConfigurationUrl), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	response := &dtm.ConfigurationsResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

// MachineTypes 机器配置
func (s *StoreEntry) MachineTypes(ctx context.Context, pastureId int64) (*dtm.MachineTypesResponse, error) {
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, MachineTypesUrl), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	response := &dtm.MachineTypesResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

// MachinesCount 返回集合个数
func (s *StoreEntry) MachinesCount(ctx context.Context, pastureId int64) (int, error) {
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, MachinesCountUrl), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return 0, xerr.WithStack(err)
	}

	response := 0
	if err = json.Unmarshal(res, &response); err != nil {
		return 0, xerr.WithStack(err)
	}
	return response, nil
}

func (s *StoreEntry) Machines(ctx context.Context, pastureId int64) (*dtm.MachineResponse, error) {
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, MachinesUrl), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	zaplog.Info("Machines", zap.Any("res", string(res)))

	response := &dtm.MachineResponse{}
	if err = json.Unmarshal(res, &response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

func (s *StoreEntry) IsCheckCompanyToken(ctx context.Context, pastureId int64) error {
	if CompanyTokenValue == "" {
		companyToken, err := s.CompanyToken(ctx, pastureId)
		if err != nil {
			return xerr.WithStack(err)
		}
		if companyToken.Token == "" {
			return xerr.WithStack(xerr.New("获取公司token失败"))
		}
		CompanyTokenValue = companyToken.Token
	}
	return nil
}

// RefusedByDayList dtm 剩料数据
func (s *StoreEntry) RefusedByDayList(ctx context.Context, skip int, pastureId int64) (interface{}, error) {
	urlValue := url.Values{}
	urlValue.Add("$top", fmt.Sprintf("%d", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Request.Top))
	urlValue.Add("$count", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Request.Count)
	urlValue.Add("$orderby", "refusedDate desc")
	urlValue.Add("$skip", fmt.Sprintf("%d", skip))
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s?%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, RefusedByDayListUrl, urlValue.Encode()), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})

	if err != nil {
		return nil, xerr.WithStack(err)
	}
	response := &dtm.RefusedByDayResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

// BatchHistByDayList dtm 批次记录数据
func (s *StoreEntry) BatchHistByDayList(ctx context.Context, skip int, pastureId int64) (interface{}, error) {
	todayTime := time.Now()
	tomorrow := todayTime.AddDate(0, 0, 1)
	UrlValue := url.Values{}
	UrlValue.Add("$top", fmt.Sprintf("%d", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Request.Top))
	UrlValue.Add("$count", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Request.Count)
	UrlValue.Add("$skip", fmt.Sprintf("%d", skip))
	UrlValue.Add("$orderby", "elabLoadId desc")
	UrlValue.Add("$filter", fmt.Sprintf("(loadDate ge %sT00:00:00Z) and (loadDate lt %sT00:00:00Z)", todayTime.Format(pkg.LayoutYear), tomorrow.Format(pkg.LayoutYear)))

	urlPath := fmt.Sprintf("%s%s?%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, BatchHistListUrl, UrlValue.Encode())
	res, err := s.HttpClient.DoGet(urlPath, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}
	zaplog.Info("BatchHistByDayList", zap.Any("urlPath", urlPath), zap.Any("res", string(res)))
	response := &dtm.BatchHistResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

func (s *StoreEntry) BatchHistDetail(ctx context.Context, elAbLoadId int, pastureId int64) (*dtm.BatchHistDetailResponse, error) {
	urlPath := fmt.Sprintf("%s%s(elabLoadId=%d)", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, BatchHistDetailUrl, elAbLoadId)
	res, err := s.HttpClient.DoGet(urlPath, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})

	if err != nil {
		zaplog.Error("BatchHistDetail",
			zap.Any("url", urlPath),
			zap.Any("err", err),
			zap.Any("CompanyTokenValue", CompanyTokenValue),
		)
		return nil, xerr.WithStack(err)
	}
	response := &dtm.BatchHistDetailResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

// FormulationByDataList dtm 配方数据
func (s *StoreEntry) FormulationByDataList(ctx context.Context, skip int, pastureId int64) (interface{}, error) {
	UrlValue := url.Values{}
	UrlValue.Add("$top", fmt.Sprintf("%d", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Request.Top))
	UrlValue.Add("$count", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Request.Count)
	UrlValue.Add("$orderby", fmt.Sprintf("%s", "recipeId desc"))
	UrlValue.Add("$filter", fmt.Sprintf("%s", "enabled eq true"))
	UrlValue.Add("$skip", fmt.Sprintf("%d", skip))
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s?%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, FormulationListUrl, UrlValue.Encode()), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})

	if err != nil {
		return nil, xerr.WithStack(err)
	}
	response := &dtm.FormulationResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

// DtmBatch dtm 批次数据
func (s *StoreEntry) DtmBatch(ctx context.Context, skip int, filter string, pastureId int64) (*dtm.BatchResponse, error) {
	UrlValue := url.Values{}
	UrlValue.Add("$top", fmt.Sprintf("%d", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Request.Top))
	UrlValue.Add("$count", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].Request.Count)
	UrlValue.Add("$orderby", fmt.Sprintf("%s", "batchId desc"))
	UrlValue.Add("$skip", fmt.Sprintf("%d", skip))
	if filter != "" {
		UrlValue.Add("$filter", fmt.Sprintf("( enabled eq true ) and ( %s )", filter))
	} else {
		UrlValue.Add("$filter", "enabled eq true")
	}

	urlPath := fmt.Sprintf("%s%s?%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, BatchUrl, UrlValue.Encode())
	res, err := s.HttpClient.DoGet(urlPath, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})

	if err != nil {
		return nil, xerr.WithStack(err)
	}
	response := &dtm.BatchResponse{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}
